package com.weishenai.customerassistant.security.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.weishenai.customerassistant.common.Const;
import com.weishenai.customerassistant.exception.CaptchaException;
import com.weishenai.customerassistant.security.handler.LoginFailureHandler;
import com.weishenai.customerassistant.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @Auther: weishenai
 * @Date: 2021/12/09/18:23
 * @Description: 从 httpRequest 中获取json格式的参数并验证
 */
@Slf4j
public class JsonAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    @Autowired
    RedisUtils redisUtils;

    @Autowired
    LoginFailureHandler loginFailureHandler;


    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (!"POST".equals(request.getMethod())) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }
        //判断Content-type 类型
        if (request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)) {
            //获取请求内容
            Map<String, String> loginData = new HashMap<>();

            try {
                loginData = new ObjectMapper().readValue(request.getInputStream(), Map.class);

                String username = loginData.get(getUsernameParameter());
                String password = loginData.get(getPasswordParameter());
                String code = loginData.get("code");
                String token = loginData.get("token");
                validate(code, token);
                // 创建 Authentication
                UsernamePasswordAuthenticationToken authentication =
                        new UsernamePasswordAuthenticationToken(username, password);
                setDetails(request, authentication);
                // 执行身份验证
                return this.getAuthenticationManager().authenticate(authentication);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (CaptchaException e) {
                log.info(e.getMessage());
                // 交给登录失败处理器处理
                try {
                    loginFailureHandler.onAuthenticationFailure(request, response, e);
                } catch (IOException ex) {
                    ex.printStackTrace();
                } catch (ServletException ex) {
                    ex.printStackTrace();
                }
            }
        }
        // 兼容表单登陆
        return super.attemptAuthentication(request, response);
    }

    /**
     * @Description: 验证码校验
     * @Param: [request]
     * @return: void
     * @Author: weishenai
     * @Date: 2021/12/9
     */
    private void validate(String code, String token) throws CaptchaException {
        if (StringUtils.isBlank(code) || StringUtils.isBlank(token)) {
            throw new CaptchaException("验证码不能为空");
        }
        if (!code.equals(redisUtils.hget(Const.CAPTCHA_KEY, token))) {
            throw new CaptchaException("验证码不正确");
        }
        // 一次性使用
        redisUtils.hdel(Const.CAPTCHA_KEY, token);
    }
}
